using BepuPhysics.Collidables;
using BepuPhysics.CollisionDetection;
using BepuPhysics.Trees;
using BepuUtilities;
using BepuUtilities.Memory;
using System;
using System.Diagnostics;

namespace BepuPhysics
{
    /// <summary>
    /// 协调完整运动仿真的记账和执行。
    /// </summary>
    public partial class Simulation : IDisposable
    {
        public IslandAwakener Awakener { get; private set; }
        public IslandSleeper Sleeper { get; private set; }
        public Bodies Bodies { get; private set; }
        public Statics Statics { get; private set; }
        public Shapes Shapes { get; private set; }
        public BodyLayoutOptimizer BodyLayoutOptimizer { get; private set; }
        public ConstraintLayoutOptimizer ConstraintLayoutOptimizer { get; private set; }
        public BatchCompressor SolverBatchCompressor { get; private set; }
        public Solver Solver { get; private set; }
        public IPoseIntegrator PoseIntegrator { get; private set; }
        public BroadPhase BroadPhase { get; private set; }
        public CollidableOverlapFinder BroadPhaseOverlapFinder { get; private set; }
        public NarrowPhase NarrowPhase { get; private set; }

        SimulationProfiler profiler = new SimulationProfiler(13);
        /// <summary>
        /// 获取模拟探查器。请注意,SimulationProfiler实现仅在使用概要文件编译符号编译库时才存在;如果未定义,则返回时间未定义。
        /// </summary>
        public SimulationProfiler Profiler { get { return profiler; } }

        // 帮助者至少在两个阶段共享。
        internal ConstraintRemover constraintRemover;

        /// <summary>
        /// 获取用于填充引擎中的持久性结构和主线程临时资源的主内存池。
        /// </summary>
        public BufferPool BufferPool { get; private set; }

        /// <summary>
        /// 获取用于更新模拟状态的TimeSteper。
        /// </summary>
        public ITimestepper Timestepper { get; private set; }

        /// <summary>
        /// 获取或设置在使用多线程时是否使用确定性时间步。设置为true时,额外的时间用于对约束添加和传输进行排序。
        /// 请注意,这只会在本地影响确定性-不同的处理器体系结构可能会以不同的方式实现指令。
        /// </summary>
        public bool Deterministic { get; set; }

        protected Simulation(BufferPool bufferPool, SimulationAllocationSizes initialAllocationSizes, int solverIterationCount, int solverFallbackBatchThreshold, ITimestepper timestepper)
        {
            BufferPool = bufferPool;
            Shapes = new Shapes(bufferPool, initialAllocationSizes.ShapesPerType);
            BroadPhase = new BroadPhase(bufferPool, initialAllocationSizes.Bodies, initialAllocationSizes.Bodies + initialAllocationSizes.Statics);
            Bodies = new Bodies(bufferPool, Shapes, BroadPhase,
                initialAllocationSizes.Bodies,
                initialAllocationSizes.Islands,
                initialAllocationSizes.ConstraintCountPerBodyEstimate);
            Statics = new Statics(bufferPool, Shapes, Bodies, BroadPhase, initialAllocationSizes.Statics);

            Solver = new Solver(Bodies, BufferPool, solverIterationCount, solverFallbackBatchThreshold,
                initialCapacity: initialAllocationSizes.Constraints,
                initialIslandCapacity: initialAllocationSizes.Islands,
                minimumCapacityPerTypeBatch: initialAllocationSizes.ConstraintsPerTypeBatch);
            constraintRemover = new ConstraintRemover(BufferPool, Bodies, Solver);
            Sleeper = new IslandSleeper(Bodies, Solver, BroadPhase, constraintRemover, BufferPool);
            Awakener = new IslandAwakener(Bodies, Statics, Solver, BroadPhase, Sleeper, bufferPool);
            Statics.awakener = Awakener;
            Solver.awakener = Awakener;
            Bodies.Initialize(Solver, Awakener, Sleeper);
            SolverBatchCompressor = new BatchCompressor(Solver, Bodies);
            BodyLayoutOptimizer = new BodyLayoutOptimizer(Bodies, BroadPhase, Solver, bufferPool);
            ConstraintLayoutOptimizer = new ConstraintLayoutOptimizer(Bodies, Solver);
            Timestepper = timestepper;

        }

        /// <summary>
        /// 使用指定的窄阶段回调构造支持动态移动和约束的模拟。
        /// </summary>
        /// <param name="BufferPool">用于填充引擎中的持久结构和主线程临时资源的缓冲池。</param>
        /// <param name="textPhaseCallback">要在窄阶段中使用的回调。</param>
        /// <param name="poseIntegratorCallback">要在姿势积分器中使用的回调。</param>
        /// <param name="timestepper">定义应如何更新模拟状态的TimeStepper。</param>
        /// <param name="solverIterationCount">求解器应使用的迭代次数。</param>
        /// <param name="solverFallbackBatchThreshold">在回退到质量较低的Jacobi混合求解器之前,求解器应保持的同步批次数。</param>
        /// <param name="initialAllocationSizes">用于初始化模拟的分配大小。如果保留为NULL,则选择默认值。</param>
        /// <Returns>新建模拟。</Returns>
        public static Simulation Create<TNarrowPhaseCallbacks, TPoseIntegratorCallbacks>(
            BufferPool bufferPool, TNarrowPhaseCallbacks narrowPhaseCallbacks, TPoseIntegratorCallbacks poseIntegratorCallbacks, ITimestepper timestepper,
            int solverIterationCount = 8, int solverFallbackBatchThreshold = 64, SimulationAllocationSizes? initialAllocationSizes = null)
            where TNarrowPhaseCallbacks : struct, INarrowPhaseCallbacks
            where TPoseIntegratorCallbacks : struct, IPoseIntegratorCallbacks
        {
            if (initialAllocationSizes == null)
            {
                initialAllocationSizes = new SimulationAllocationSizes
                {
                    Bodies = 4096,
                    Statics = 4096,
                    ShapesPerType = 128,
                    ConstraintCountPerBodyEstimate = 8,
                    Constraints = 16384,
                    ConstraintsPerTypeBatch = 256
                };
            }

            var simulation = new Simulation(bufferPool, initialAllocationSizes.Value, solverIterationCount, solverFallbackBatchThreshold, timestepper);
            simulation.PoseIntegrator = new PoseIntegrator<TPoseIntegratorCallbacks>(simulation.Bodies, simulation.Shapes, simulation.BroadPhase, poseIntegratorCallbacks);
            var narrowPhase = new NarrowPhase<TNarrowPhaseCallbacks>(simulation,
                DefaultTypes.CreateDefaultCollisionTaskRegistry(), DefaultTypes.CreateDefaultSweepTaskRegistry(),
                narrowPhaseCallbacks, initialAllocationSizes.Value.Islands + 1);
            DefaultTypes.RegisterDefaults(simulation.Solver, narrowPhase);
            simulation.NarrowPhase = narrowPhase;
            simulation.Sleeper.pairCache = narrowPhase.PairCache;
            simulation.Awakener.pairCache = narrowPhase.PairCache;
            simulation.Solver.pairCache = narrowPhase.PairCache;
            simulation.BroadPhaseOverlapFinder = new CollidableOverlapFinder<TNarrowPhaseCallbacks>(narrowPhase, simulation.BroadPhase);

            return simulation;
        }



        private int ValidateAndCountShapefulBodies(ref BodySet bodySet, ref Tree tree, ref Buffer<CollidableReference> leaves)
        {
            int shapefulBodyCount = 0;
            for (int i = 0; i < bodySet.Count; ++i)
            {
                ref var collidable = ref bodySet.Collidables[i];
                if (collidable.Shape.Exists)
                {
                    Debug.Assert(collidable.BroadPhaseIndex >= 0 && collidable.BroadPhaseIndex < tree.LeafCount);
                    ref var leaf = ref leaves[collidable.BroadPhaseIndex];
                    Debug.Assert(leaf.StaticHandle.Value == bodySet.IndexToHandle[i].Value);
                    Debug.Assert(leaf.Mobility == CollidableMobility.Dynamic || leaf.Mobility == CollidableMobility.Kinematic);
                    ++shapefulBodyCount;
                }
            }
            return shapefulBodyCount;
        }


        [Conditional("DEBUG")]
        internal void ValidateCollidables()
        {
            var activeShapefulBodyCount = ValidateAndCountShapefulBodies(ref Bodies.ActiveSet, ref BroadPhase.ActiveTree, ref BroadPhase.activeLeaves);
            Debug.Assert(BroadPhase.ActiveTree.LeafCount == activeShapefulBodyCount);

            int inactiveShapefulBodyCount = 0;

            for (int setIndex = 1; setIndex < Bodies.Sets.Length; ++setIndex)
            {
                ref var set = ref Bodies.Sets[setIndex];
                if (set.Allocated)
                {
                    inactiveShapefulBodyCount += ValidateAndCountShapefulBodies(ref set, ref BroadPhase.StaticTree, ref BroadPhase.staticLeaves);
                }
            }
            Debug.Assert(inactiveShapefulBodyCount + Statics.Count == BroadPhase.StaticTree.LeafCount);
            for (int i = 0; i < Statics.Count; ++i)
            {
                ref var collidable = ref Statics.Collidables[i];
                Debug.Assert(collidable.Shape.Exists, "All static collidables must have shapes. That's their only purpose.");

                Debug.Assert(collidable.BroadPhaseIndex >= 0 && collidable.BroadPhaseIndex < BroadPhase.StaticTree.LeafCount);
                ref var leaf = ref BroadPhase.staticLeaves[collidable.BroadPhaseIndex];
                Debug.Assert(leaf.StaticHandle.Value == Statics.IndexToHandle[i].Value);
                Debug.Assert(leaf.Mobility == CollidableMobility.Static);
            }

            // 确保两个宽阔的阶段树之间没有重复项。
            for (int i = 0; i < BroadPhase.ActiveTree.LeafCount; ++i)
            {
                var activeLeaf = BroadPhase.activeLeaves[i];
                for (int j = 0; j < BroadPhase.StaticTree.LeafCount; ++j)
                {
                    Debug.Assert(BroadPhase.staticLeaves[j].Packed != activeLeaf.Packed);
                }
            }

        }

        // 这些函数充当常见执行模式的便利包装器。它们可以在自定义时间步长中混合和匹配,或者对于某些高级用例,可以直接调用。
        /// <summary>
        /// 执行休眠阶段,移动候选人
        /// </summary>
        /// <param name="threadDispatcher">用于休眠程序执行的线程调度程序(如果有)。</param>
        public void Sleep(IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(Sleeper);
            Sleeper.Update(threadDispatcher, Deterministic);
            profiler.End(Sleeper);
        }

        /// <summary>
        /// 更新活动实体的位置、速度、世界惯性、停用候选对象和边界框。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IntegrateBodiesAndUpdateBoundingBoxes(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(PoseIntegrator);
            PoseIntegrator.IntegrateBodiesAndUpdateBoundingBoxes(dt, BufferPool, threadDispatcher);
            profiler.End(PoseIntegrator);
        }

        /// <summary>
        /// 通过推测性积分速度来预测活动物体的边界框。实际上不会修改车身速度。更新停用候选人资格。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void PredictBoundingBoxes(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(PoseIntegrator);
            PoseIntegrator.PredictBoundingBoxes(dt, BufferPool, threadDispatcher);
            profiler.End(PoseIntegrator);
        }

        /// <summary>
        /// 更新激活实体的速度、世界空间惯性、边界框和停用候选对象。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IntegrateVelocitiesBoundsAndInertias(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(PoseIntegrator);
            PoseIntegrator.IntegrateVelocitiesBoundsAndInertias(dt, BufferPool, threadDispatcher);
            profiler.End(PoseIntegrator);
        }

        /// <summary>
        /// 更新活动体的速度和世界空间惯性。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IntegrateVelocitiesAndUpdateInertias(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(PoseIntegrator);
            PoseIntegrator.IntegrateVelocitiesAndUpdateInertias(dt, BufferPool, threadDispatcher);
            profiler.End(PoseIntegrator);
        }

        /// <summary>
        /// 更新活动实体的姿势。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IntegratePoses(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(PoseIntegrator);
            PoseIntegrator.IntegratePoses(dt, BufferPool, threadDispatcher);
            profiler.End(PoseIntegrator);
        }

        /// <summary>
        /// 更新当前主体边界框的宽阶段结构,查找可能发生冲突的对,然后对所有此类对执行窄阶段。为求解器生成接触约束。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void CollisionDetection(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(BroadPhase);
            BroadPhase.Update(threadDispatcher);
            profiler.End(BroadPhase);

            profiler.Start(BroadPhaseOverlapFinder);
            BroadPhaseOverlapFinder.DispatchOverlaps(dt, threadDispatcher);
            profiler.End(BroadPhaseOverlapFinder);

            profiler.Start(NarrowPhase);
            NarrowPhase.Flush(threadDispatcher);
            profiler.End(NarrowPhase);
        }

        /// <summary>
        /// 使用当前实体速度以增量方式更新所有激活的接触约束穿透深度。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IncrementallyUpdateContactConstraints(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(Solver);
            Solver.IncrementallyUpdateContactConstraints(dt, threadDispatcher);
            profiler.End(Solver);
        }

        /// <summary>
        /// 求解仿真中的所有激活约束。
        /// </summary>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void Solve(float dt, IThreadDispatcher threadDispatcher = null)
        {
            profiler.Start(Solver);
            Solver.Solve(dt, threadDispatcher);
            profiler.End(Solver);
        }

        /// <summary>
        /// 增量地改进实体和约束存储以获得更好的性能。
        /// </summary>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void IncrementallyOptimizeDataStructures(IThreadDispatcher threadDispatcher = null)
        {
            // 请注意,约束优化应在实体优化之后执行,因为实体优化会移动实体,因此会影响最佳约束位置。
            // TODO：这些优化器阶段的顺序与性能相关,即使它们对正确性没有任何影响。
            // 您可能希望在不同位置尝试它们,看看它们如何影响缓存驻留。
            profiler.Start(BodyLayoutOptimizer);
            BodyLayoutOptimizer.IncrementalOptimize();
            profiler.End(BodyLayoutOptimizer);

            profiler.Start(ConstraintLayoutOptimizer);
            ConstraintLayoutOptimizer.Update(BufferPool, threadDispatcher);
            profiler.End(ConstraintLayoutOptimizer);

            profiler.Start(SolverBatchCompressor);
            SolverBatchCompressor.Compress(BufferPool, threadDispatcher, threadDispatcher != null && Deterministic);
            profiler.End(SolverBatchCompressor);
        }

        // TODO：我想知道人们会不会滥用dt作为参数,以至于我们应该把它变成一个字段,就像在v1中一样。
        /// <summary>
        /// 执行给定长度的一个时间步。
        /// </summary>
        /// <remarks>
        /// 要小心可变的时间步长。它们可能会损害稳定。只要有可能,请在多个帧中保持相同的时间步长,除非您有特定的原因不这样做。
        /// </remarks>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="threadDispatcher">用于执行的线程调度程序(如果有)。</param>
        public void Timestep(float dt, IThreadDispatcher threadDispatcher = null)
        {
            if (dt <= 0)
                throw new ArgumentException("Timestep duration must be positive.", "dt");
            profiler.Clear();
            profiler.Start(this);

            Timestepper.Timestep(this, dt, threadDispatcher);

            profiler.End(this);
        }

        /// <summary>
        /// 清除每个对象的模拟,仅将将由顺序删除返回的内存返回给池。
        /// 其他永久性拨款,如机构集合中的拨款,将继续保留。
        /// </summary>
        public void Clear()
        {
            Solver.Clear();
            Bodies.Clear();
            Statics.Clear();
            Shapes.Clear();
            BroadPhase.Clear();
            NarrowPhase.Clear();
            Sleeper.Clear();
        }

        /// <summary>
        /// 增加任何太小而无法容纳分配目标的缓冲区的分配大小。
        /// </summary>
        /// <remarks>
        /// <para>
        /// 分配的缓冲区的最终大小由分配器约束。它不能保证与目标完全相等,但可以保证至少一样大。
        /// </para>
        /// <para>
        /// 这主要是一个方便的功能。它在内部做的一切都可以在外部做。
        /// 例如,如果只需要调整类型批处理的大小,则可以直接使用求解器自己的函数。
        /// </para>
        /// </remarks>
        /// <param name="allocationTarget">保证足够大小的分配大小。</param>
        public void EnsureCapacity(SimulationAllocationSizes allocationTarget)
        {
            Solver.EnsureSolverCapacities(allocationTarget.Bodies, allocationTarget.Constraints);
            Solver.MinimumCapacityPerTypeBatch = Math.Max(allocationTarget.ConstraintsPerTypeBatch, Solver.MinimumCapacityPerTypeBatch);
            Solver.EnsureTypeBatchCapacities();
            NarrowPhase.PairCache.EnsureConstraintToPairMappingCapacity(Solver, allocationTarget.Constraints);
            // 请注意,主体集必须位于主体布局优化器之前;主体布局优化器的大小取决于主体集。
            Bodies.EnsureCapacity(allocationTarget.Bodies);
            Bodies.MinimumConstraintCapacityPerBody = allocationTarget.ConstraintCountPerBodyEstimate;
            Bodies.EnsureConstraintListCapacities();
            Sleeper.EnsureSetsCapacity(allocationTarget.Islands + 1);
            Statics.EnsureCapacity(allocationTarget.Statics);
            Shapes.EnsureBatchCapacities(allocationTarget.ShapesPerType);
            BroadPhase.EnsureCapacity(allocationTarget.Bodies, allocationTarget.Bodies + allocationTarget.Statics);
        }


        /// <summary>
        /// 增加任何太小而无法容纳分配目标的缓冲区的分配大小,并减小任何不必要地大的缓冲区的分配大小。
        /// </summary>
        /// <remarks>
        /// <para>
        /// 分配的缓冲区的最终大小由分配器约束。它不能保证与目标完全相等,但可以保证至少一样大。
        /// </para>
        /// <para>
        /// 这主要是一个方便的功能。它在内部做的一切都可以在外部做。
        /// 例如,如果只需要调整类型批处理的大小,则可以直接使用求解器自己的函数。
        /// </para>
        /// </remarks>
        /// <param name="allocationTarget">保证足够大小的分配大小。</param>
        public void Resize(SimulationAllocationSizes allocationTarget)
        {
            Solver.ResizeSolverCapacities(allocationTarget.Bodies, allocationTarget.Constraints);
            Solver.MinimumCapacityPerTypeBatch = allocationTarget.ConstraintsPerTypeBatch;
            Solver.ResizeTypeBatchCapacities();
            NarrowPhase.PairCache.ResizeConstraintToPairMappingCapacity(Solver, allocationTarget.Constraints);
            // 请注意,主体集必须位于主体布局优化器之前;主体布局优化器的大小取决于主体集。
            Bodies.Resize(allocationTarget.Bodies);
            Bodies.MinimumConstraintCapacityPerBody = allocationTarget.ConstraintCountPerBodyEstimate;
            Bodies.ResizeConstraintListCapacities();
            Sleeper.ResizeSetsCapacity(allocationTarget.Islands + 1);
            Statics.Resize(allocationTarget.Statics);
            Shapes.ResizeBatches(allocationTarget.ShapesPerType);
            BroadPhase.Resize(allocationTarget.Bodies, allocationTarget.Bodies + allocationTarget.Statics);
        }

        /// <summary>
        /// 清除每个对象的模拟,并将所有池化内存返回到缓冲池。使模拟处于不可用状态。
        /// </summary>
        public void Dispose()
        {
            Clear();
            Sleeper.Dispose();
            Solver.Dispose();
            BroadPhase.Dispose();
            NarrowPhase.Dispose();
            Bodies.Dispose();
            Statics.Dispose();
            Shapes.Dispose();
        }
    }
}
